from django.http import HttpResponse, Http404
#Request Context is what lets the CSRF Token work
from django.template import Context, loader, RequestContext
from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.views.decorators.csrf import csrf_protect
from django.db.models import Q
import datetime

from ocms.eventmanager.models import *
from ocms.eventmanager.forms import *
from ocms.eventmanager.util import *
from ocms.eventmanager.gcalendar import *

from django.conf import settings

def index(request):
	'''
	This is the base page of the application
	It shows the current items (based on user permissions) and the upcomming schedule
	'''
	my_approved_event_list = None
	my_review_list = None
	global_appsec_events = None
	regional_local_training_events = None
	partner_promo_events = None
	approved_event_list = Event.objects.filter(event_status='A', approval_status='A').order_by('Start_Date')
	
	if (request.user.is_authenticated()):
		# Pull all of the active events where this user is on the planning team.
		my_approved_event_list = Event.objects.filter(event_status='A', approval_status="A", planning_team=request.user).order_by('Start_Date')
		if has_voting_rights(request.user) or request.user.is_staff or request.user.is_superuser:
			#superusers get all active events
			my_review_list = Event.objects.filter(event_status='A').filter(Q(approval_status='U') | Q(approval_status='H')).order_by('date_created')
		else:
			#non superusers get all events for which they are on the planning team
			my_review_list = Event.objects.filter(Q(approval_status='U') | Q(approval_status='H')).filter(event_status='A', planning_team=request.user).order_by('Start_Date')

		if ((request.user.is_superuser) or (request.user.is_staff)):
			#fetch stuff for generating wikicode
			global_appsec_events = Event.objects.filter(content_type__model='globalappsecevent').filter(event_status='A', approval_status="A").order_by('-Start_Date').reverse()
			regional_local_training_events = Event.objects.filter(Q(content_type__model='regionalevent') | Q(content_type__model='localevent') | Q(content_type__model='localevent')).filter(event_status='A', approval_status="A").order_by('-Start_Date').reverse()
			partner_promo_events = Event.objects.filter(Q(content_type__model='promotionalevent') | Q(content_type__model='partnerevent')).filter(event_status='A', approval_status="A").order_by('-Start_Date').reverse()
		
	c = Context({
		'my_approved_event_list': my_approved_event_list,
		'my_review_list': my_review_list,
		'approved_event_list': approved_event_list,
		'global_appsec_events': global_appsec_events,
		'regional_local_training_events': regional_local_training_events,
		'partner_promo_events': partner_promo_events,
		'user_voted_events': Event.objects.filter(vote__user=request.user.id), 
		'can_vote': has_voting_rights(request.user),
		'active_planner_emails': active_planner_emails_sql(),
	})
	return render_to_response('events/index.html', c, context_instance=RequestContext(request))

def archive(request):
	'''
	Shows all approved, archived events
	It shows the current items (based on user permissions) and the upcomming schedule
	'''
	events = Event.objects.filter(event_status='X', approval_status='A').order_by('Start_Date')

	c = Context({
		'events': events,
	})
	return render_to_response('events/archive.html', c, context_instance=RequestContext(request))

def all(request):
	'''
	Shows all approved, archived events
	It shows the current items (based on user permissions) and the upcomming schedule
	'''
	active_events = Event.objects.filter(event_status='A').order_by('Start_Date')
	archive_events = Event.objects.filter(event_status='X').order_by('Start_Date')

	c = Context({
		'active_events': active_events,
		'archive_events': archive_events,
	})
	return render_to_response('events/all.html', c, context_instance=RequestContext(request))

@csrf_protect    
def detail(request, event_id):
	'''
	Displays a full detail page of a particular event
	Unprotected page
	Access control in isPlanner and can_vote options for display control (convienience auth only)
	'''
	event = get_object_or_404(Event, pk=event_id)
	event = event.cast()  
	form = getForm(str(event.content_type), instance=event)
	#custom context parameters
	c = {	'event': event, 
			'form': form, 
			'event_type': str(event.content_type).title(),
			'isPlanner': (has_voting_rights(request.user) or (request.user in event.planning_team.all()) or request.user.is_staff),
			'vote_opts': VOTE_CHOICES,
			'votes': Vote.objects.filter(event=event),
			'user_vote': Vote.objects.filter(event=event).filter(user=request.user.id), 
			'can_vote': has_voting_rights(request.user),
	}
	return render_to_response('events/detail.html', c , context_instance=RequestContext(request))

@login_required
@csrf_protect    
def edit(request, event_id):
	'''
	Login required
	Processes form updates to events
	'''
	event = get_object_or_404(Event, pk=event_id)
	event = event.cast()

	#check to see if the current user is a superuser or a member of this event's planning team
	if (has_voting_rights(request.user) or (request.user in event.planning_team.all()) or request.user.is_staff):
		if request.method == 'POST':
			form = getForm(str(event.content_type), request.POST, request.FILES, instance=event)
			if form.is_valid():
				form.save()
				messages.success(request, 'Event details updated.')
			else:
				messages.error(request, 'Please correct the errors below')
				c = {	'event': event, 
						'form': form, 
						'event_type': str(event.content_type).title(),
						'isPlanner': (has_voting_rights(request.user) or (request.user in event.planning_team.all()) or request.user.is_staff),
						'vote_opts': VOTE_CHOICES,
						'votes': Vote.objects.filter(event=event).filter(user=request.user.id), 
						'can_vote': has_voting_rights(request.user), 
				}
				return render_to_response('events/detail.html', c , context_instance=RequestContext(request))
	else:
		#user isn't a superuser nor a planner for this event
		messages.warning(request, 'You do not have permission to edit this event')

	#all roads lead back to the detail form
	return redirect('/events/'+str(event.id)+'/')

@login_required
@csrf_protect    
def add(request):
	if request.method == 'GET':
		#display event request code
		c = {
				'event_types': EventType.objects.all().order_by('long_name'),
		}
		return render_to_response('events/typeselect.html', c , context_instance=RequestContext(request))
	elif request.method == 'POST':
		event_type = False
		form_complete = False
		
		if (request.POST.get("event_type")):
			event_type = str(request.POST.get("event_type"))
		
		if (request.POST.get("FORM_COMPLETE")):
				form_complete = str(request.POST.get("FORM_COMPLETE"))
		
		if ((event_type) and (not form_complete)):
			#we have a selected event type
			#display blank form
			form = getForm(event_type)
			c = {	'form': form,
					'event_type': event_type, 
			}				
			return render_to_response('events/add.html', c , context_instance=RequestContext(request))
		elif ((event_type) and (form_complete)):
			#here we save the form (or at least try to
			form = getForm(event_type, request.POST, request.FILES)
			if form.is_valid():
				instance = form.save()
				messages.success(request, 'Event created.')

				sendEmail(instance, "new")
			else:
				messages.error(request, 'Please correct the errors below')
				c = {	'form': form,
						'event_type': event_type, 
				}
				return render_to_response('events/add.html', c , context_instance=RequestContext(request))
		else:
			messages.error(request, 'A serious error has occurred, contact system administrator')
	else:
		messages.error(request, 'A serious error has occurred, contact system administrator')

	#If they plan to get merch, redirect them to the merch site, otherwise to the main page
	if (request.POST.get("merch_requested")):
		return redirect(settings.MERCH_SITE_URL)	
	else:	
		return redirect('/events/')	

@login_required
@csrf_protect    
def delete(request, event_id):
	event = get_object_or_404(Event, pk=event_id)
	if (has_voting_rights(request.user) or (request.user in event.planning_team.all())):
		event.delete()
		event.save()
		messages.success(request, 'Event deleted.')
		return redirect('/events/')
	else:
		messages.error(request, 'You do not have permission to delete this event')
		return redirect('/events/'+str(event.id)+'/')

@login_required
@csrf_protect
def vote(request, event_id):
	event = get_object_or_404(Event, pk=event_id)
	if has_voting_rights(request.user):
		if not Vote.objects.filter(event=event).filter(user=request.user.id):
			selected_choice = request.POST['choice']
			try:
				e = get_object_or_404(Event, pk=event_id)
				v = Vote(event=e, user=request.user, vote=selected_choice, vote_date=datetime.datetime.now())
				v.save()
				messages.success(request, 'Vote Recorded')
			except:
				messages.error(request, 'Error Recording your vote')
			
			try:
				#check event status
				e.checkStatus()
			except:
				messages.error(request, 'Error updating event status')
		else:
			messages.error(request, 'You\'ve already voted')
	else:
		messages.error(request, 'You don\'t have permission to vote')
    
	# Redisplay the poll voting form.
	return redirect('/events/'+str(event.id)+'/')

@login_required
@csrf_protect
def hold(request, event_id):
	event = get_object_or_404(Event, pk=event_id)
	if has_voting_rights(request.user):
		if not Vote.objects.filter(event=event).filter(user=request.user.id):
			#try:
			e = get_object_or_404(Event, pk=event_id)
			e.hold(request.user)

	else:
		messages.error(request, 'You don\'t have permission to put an event on hold')
    
	# Redisplay the poll voting form.
	return redirect('/events/'+str(event.id)+'/')

def votingrecord(request):
	'''
	Displays metrics based on voting records
	'''
	global_appsec_stats = eventtotaler(GlobalAppSecEvent.objects.filter(approval_status='A'))
	regional_stats = eventtotaler(RegionalEvent.objects.filter(approval_status='A'))
	local_stats = eventtotaler(LocalEvent.objects.filter(approval_status='A'))
	promotional_stats = eventtotaler(PromotionalEvent.objects.filter(approval_status='A'))
	partner_stats = eventtotaler(PartnerEvent.objects.filter(approval_status='A'))
	
			
	stats = [
		global_appsec_stats,
		regional_stats,
		local_stats,
		promotional_stats,
		partner_stats,
	]
	
	member_voting_stats = member_voting_stats_engine()
	
	c = Context({
				'stats': stats,
				'member_voting_stats': member_voting_stats,
	})
	return render_to_response('events/voting.html', c, context_instance=RequestContext(request))

def uservotingrecord(request, user_id):
	'''
	Displays metrics based on voting records
	'''
	user = get_object_or_404(User, pk=user_id)
	
	global_appsec_stats = usertotaler(user, GlobalAppSecEvent.objects.all())
	regional_stats = usertotaler(user, RegionalEvent.objects.all())
	local_stats = usertotaler(user, LocalEvent.objects.all())
	promotional_stats = usertotaler(user, PromotionalEvent.objects.all())
	partner_stats = usertotaler(user, PartnerEvent.objects.all())
	
			
	event_stats = [
		global_appsec_stats,
		regional_stats,
		local_stats,
		promotional_stats,
		partner_stats,
	]
	
	c = Context({
				'event_stats': event_stats,
				'member_stat': member_voting_stats(user),
				'votes': Vote.objects.filter(user=user),
				'user': user,
	})
	return render_to_response('events/user_voting_record.html', c, context_instance=RequestContext(request))

def eventtotaler(events):
	count = 0
	sum = datetime.timedelta(milliseconds=0)
	min = {'event': None, 'value': datetime.timedelta(days=500)}
	max = {'event': None, 'value': datetime.timedelta(milliseconds=0)}
	for event in events:
		count += 1
		value = abs(event.approval_date - event.date_created)
		sum += value
		
		if value <= min['value']:
			min['value'] = value
			min['event'] = event
			
		if value >= max['value']:
			max['value'] = value
			max['event'] = event
			
	return {'type':str(event.content_type).title(), 'count': count, 'average': sum/count, 'min':min, 'max':max}

def member_voting_stats_engine():
	gcc_members = getGCCMembers()
	events = Event.objects.all()
	member_stats = []
	
	for member in gcc_members:
		member_stats.append(member_voting_stats(member))
	
	return member_stats
	
def member_voting_stats(member):
	events = Event.objects.all()
	count = 0
	approve = 0
	reject = 0
	abstain = 0
	
	sum = datetime.timedelta(milliseconds=0)
	min = {'event': None, 'value': datetime.timedelta(days=500)}
	max = {'event': None, 'value': datetime.timedelta(milliseconds=0)}

	user_votes = Vote.objects.filter(user=member)
	for vote in user_votes:
		count += 1
		value = abs(vote.vote_date - vote.event.date_created)
		sum += value			

		if vote.vote == 'A':
			approve += 1
		elif vote.vote == 'R':
			reject += 1
		elif vote.vote == 'O':
			abstain += 1
	
		if value <= min['value']:
			min['value'] = value
			min['event'] = vote.event
		
			if value >= max['value']:
				max['value'] = value
				max['event'] = vote.event
	
	return({'member':member, 'count': count, 'approve': approve, 'reject': reject, 'abstain': abstain, 'novote':len(events) - count, 'average': sum / count, 'min':min, 'max':max})		


def usertotaler(member, events):
	
	count = 0
	approve = 0
	reject = 0
	abstain = 0
	sum = datetime.timedelta(milliseconds=0)
	min = {'event': None, 'value': datetime.timedelta(days=500)}
	max = {'event': None, 'value': datetime.timedelta(milliseconds=0)}
	
	for event in events:
		user_votes = Vote.objects.filter(event=event, user=member)
		for vote in user_votes:
			count += 1
			value = abs(vote.vote_date - vote.event.date_created)
			sum += value			

			if vote.vote == 'A':
				approve += 1
			elif vote.vote == 'R':
				reject += 1
			elif vote.vote == 'O':
				abstain += 1
	
			if value <= min['value']:
				min['value'] = value
				min['event'] = vote.event
		
			if value >= max['value']:
				max['value'] = value
				max['event'] = vote.event
			
	return({'type':str(events[0].content_type).title(), 'member':member.first_name + " " + member.last_name, 'count': count, 'approve': approve, 'reject': reject, 'abstain': abstain, 'novote':len(events) - count, 'average': sum / count, 'min':min, 'max':max})		